package com.xcity.game.activity.oneyuan;

import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.List;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.alibaba.fastjson.JSON;
import com.xcity.Server;
import com.xcity.db.entity.ActivityRecord;
import com.xcity.db.entity.Config;
import com.xcity.db.entity.Player;
import com.xcity.db.mapper.ActivityRecordMapper;
import com.xcity.db.mapper.ConfigMapper;
import com.xcity.game.activity.ActivityService;
import com.xcity.game.common.MessageConst;
import com.xcity.game.event.GameEvents;
import com.xcity.game.player.cache.PlayerCacheService;
import com.xcity.game.recharge.RechargeTemplate;
import com.xcity.pomelo.PomeloRoute;
import com.xcity.pomelo.push.NoticePush;
import com.xcity.pomelo.push.msg.OneYuanActivityPush;
import com.xcity.pomelo.push.msg.OneYuanActivityPush.OneYuanActivityDataPush;
import com.xcity.pomelo.request.OneYuanActivityPrizeRecordRequest;
import com.xcity.pomelo.request.OneYuanActivityRequest;
import com.xcity.pomelo.response.OneYuanActivityPrizeRecordResponse;
import com.xcity.pomelo.response.OneYuanActivityResponse;
import com.xcity.util.DBUtils;

import naga.x.App;
import naga.x.event.Event;
import naga.x.event.EventListener;
import naga.x.game.time.DayListener;
import naga.x.game.time.TimeUpdater;
import naga.x.net.Session;
import naga.x.net.annotation.OPHandler;
import naga.x.net.impl.pomelo.annotation.PomeloOP;
import naga.x.service.ServiceException;
import naga.x.util.NumberUtils;
import naga.x.util.TimeUtils;

/**
 * 一元夺宝
 * @author yang.li
 *
 */
@OPHandler
public class OneYuanBigPrizeActivityService extends ActivityService implements DayListener, EventListener {

	// 本期中奖纪录
	protected List<ActivityRecord> prizeRecords;
	// 奖池
	protected OneYuanActivityPool pool;
	
	protected static final int RECHARGE_ID = 10001;
	protected static final int NEED_RECHARGE_MONEY = 1;
	protected static final byte ACTIVITY_TYPE = 1;
	protected static final Logger LOG = LoggerFactory.getLogger(OneYuanBigPrizeActivityService.class);
	
	@Override
	public void startup() throws ServiceException {
//		// 构造一个充值模板
//		RechargeTemplate template = new RechargeTemplate();
//		template.setId(RECHARGE_ID);
//		template.setType((byte) -1);
//		template.setName("1元夺宝");
//		template.setCurrency("CNY");
//		template.setPrice(NEED_RECHARGE_MONEY);
//		template.setStone(template.getPrice() * 10);
//		template.setVisible(false); // 充值列表中对客户端不可见
//		App.getApp().getServiceManager().get(TemplateService.class).add(template);
		
		int nowPhase = getNowPhase();
		List<ActivityRecord> list = DBUtils.findLimit(ActivityRecordMapper.class, 0, -1, DBUtils.wrapParams("type", ACTIVITY_TYPE/*, "phase", nowPhase*/));
		prizeRecords = list != null ? list : new ArrayList<ActivityRecord>();
		Config cfg = DBUtils.find(Config.KEY_ONE_YUAN_ACTIVITY, ConfigMapper.class);
		if (cfg != null) {
			pool = JSON.parseObject(cfg.getValue(), OneYuanActivityPool.class);
			if (pool.isEnd()) {
				pool = new OneYuanActivityPool(nowPhase);
			}
		} else {
			pool = new OneYuanActivityPool(getNowPhase());
			DBUtils.save(new Config(Config.KEY_ONE_YUAN_ACTIVITY, JSON.toJSONString(pool)), ConfigMapper.class);
		}
		pool.load();
		App.getApp().getEventManager().register(this);
		TimeUpdater.getInstance().addDayListener(this);
//		RobotUtils.RECHARGE_TEMPLATE = template;
//		new RobotUtils(); // running fake recharge robot
		LOG.info("[1YUANLOAD]PHASE[{}]ROUND[{}]POOL[{}]MAX[{}]", pool.getPhase(), pool.getRound(), pool.getPoolValue(), pool.getPoolMax());
	}

	@Override
	public void shutdown() throws ServiceException {
		pool.save();
	}
	
	protected int getNowPhase() {
		String s = TimeUtils.format("yyyyMMdd", TimeUpdater.getInstance().now());
		return NumberUtils.parseInt(s);
	}
	
	@Override
	public synchronized boolean dayChanged() {
//		prizeRecords.clear();
		// 异步存储前一天的数据
		final OneYuanActivityPool previous = pool;
		LOG.info("[1YUAN EXPIRE]PHASE[{}]ROUND[{}]POOL[{}]MAX[{}]", pool.getPhase(), pool.getRound(), pool.getPoolValue(), pool.getPoolMax());
		App.getApp().getThreadPool().execute(new Runnable() {
			@Override
			public void run() {
				previous.save();
			}
		});
//		// 开启新一期的活动
//		pool = new OneYuanActivityPool(getNowPhase());
//		LOG.info("[1YUAN NEW]PHASE[{}]ROUND[{}]POOL[{}]MAX[{}]", pool.getPhase(), pool.getRound(), pool.getPoolValue(), pool.getPoolMax());
		return true;
	}

	@Override
	public int[] getEventTypes() {
		return new int[] { GameEvents.EVENT_RECHARGE, GameEvents.EVENT_RECHARGE_OFFLINE };
	}

	@Override
	public void handleEvent(Event event) {
		Player player = event.getParameter(0);
		int money = event.getParameter(1);
		RechargeTemplate template = event.getParameter(2);
		if (template.getId() == RECHARGE_ID && money >= NEED_RECHARGE_MONEY) {
			onRecharge(player, money);
		}
	}

	private synchronized void onRecharge(Player player, int money) {
		int overflow = pool.addRecord(player, money);
		if (pool.isEnd()) { // 该轮奖池已满，需触发抽奖
			drawPrize();
			pool.save();
			pool.nextRound();
			if (overflow > 0) {
				// 溢出部分累加到下轮活动
				pool.addRecord(player, overflow);
			}
		}
		if (player.isOnline()) {
			player.send(new OneYuanActivityPush(new OneYuanActivityDataPush(pool, player)));
		}
	}
	
	private void drawPrize() {
		long playerId = pool.drawLottery();
		ActivityRecord ar = new ActivityRecord(ACTIVITY_TYPE, pool.getPhase(), pool.getRound(), playerId);
		prizeRecords.add(ar);
		OneYuanActivityRecord record = pool.getRecord(playerId);
//		Player player = App.getApp().getServiceManager().get(ActorService.class).find(playerId);
		Player player = App.getApp().getServiceManager().get(PlayerCacheService.class).find(playerId);
		if (player != null) {
			String notice = MessageFormat.format(MessageConst.ONE_YUAN_ACTIVITY_DRAW_LOTTERY,
					player.getName(),
					pool.getPhase(),
					pool.getRound());
			Server.broadcast(new NoticePush(NoticePush.NOTICE_MARQUEE, notice));
		}
		DBUtils.save(ar, ActivityRecordMapper.class);
		LOG.info("[1YUAN PRIZE]ID[{}]MONEY[{}]PHASE[{}]ROUND[{}]", playerId, record != null ? record.getNumber() : "NULL", pool.getPhase(), pool.getRound());
	}

	@PomeloOP(PomeloRoute.ACTIVITY_ONE_YUAN_INFO)
	protected void requestInfo(Session session, OneYuanActivityRequest req) {
		Player player = session.getClient();
		session.send(new OneYuanActivityResponse(req.getSerial(), pool, player));
	}
	
	@PomeloOP(PomeloRoute.ACTIVITY_ONE_YUAN_PRIZE_RECORD)
	protected void requestPrizeRecord(Session session, OneYuanActivityPrizeRecordRequest req) {
		session.send(new OneYuanActivityPrizeRecordResponse(req.getSerial(), prizeRecords));
	}
}
